/*     */ package com.zimbra.cs.redolog.op;
/*     */ 
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import com.zimbra.cs.mailbox.MailboxOperation;
/*     */ import com.zimbra.cs.mailbox.OperationContext;
/*     */ import com.zimbra.cs.redolog.RedoCommitCallback;
/*     */ import com.zimbra.cs.redolog.RedoLogInput;
/*     */ import com.zimbra.cs.redolog.RedoLogManager;
/*     */ import com.zimbra.cs.redolog.RedoLogOutput;
/*     */ import com.zimbra.cs.redolog.RedoLogProvider;
/*     */ import com.zimbra.cs.redolog.TransactionId;
/*     */ import com.zimbra.cs.redolog.Version;
/*     */ import java.io.ByteArrayInputStream;
/*     */ import java.io.ByteArrayOutputStream;
/*     */ import java.io.EOFException;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.io.PrintStream;
/*     */ import java.io.SequenceInputStream;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Collections;
/*     */ import java.util.EnumSet;
/*     */ import java.util.HashMap;
/*     */ import java.util.Iterator;
/*     */ import java.util.LinkedList;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.Map.Entry;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public abstract class RedoableOp
/*     */ {
/*  53 */   protected static Log mLog = LogFactory.getLog(RedoableOp.class);
/*  54 */   private static String sPackageName = RedoableOp.class.getPackage().getName();
/*     */   
/*     */   public static final String REDO_MAGIC = "ZMREDO";
/*     */   
/*     */   public static final int UNKNOWN_ID = 0;
/*     */   
/*     */   public static final int MAILBOX_ID_ALL = -1;
/*     */   
/*     */   protected MailboxOperation mOperation;
/*     */   
/*     */   private Version mVersion;
/*     */   
/*     */   private TransactionId mTxnId;
/*     */   
/*     */   private boolean mActive;
/*     */   
/*     */   private long mTimestamp;
/*  71 */   private int mChangeId = -1;
/*     */   private int mChangeConstraint;
/*     */   private int mMailboxId;
/*     */   private RedoLogManager mRedoLogMgr;
/*     */   private boolean mUnloggedReplay;
/*     */   RedoCommitCallback mCommitCallback;
/*     */   protected byte[][] mSerializedByteArrayVector;
/*     */   
/*  79 */   protected RedoableOp(MailboxOperation op) { this.mOperation = op;
/*  80 */     this.mRedoLogMgr = RedoLogProvider.getInstance().getRedoLogManager();
/*  81 */     this.mVersion = new Version();
/*  82 */     this.mTxnId = null;
/*  83 */     this.mActive = false;
/*  84 */     this.mMailboxId = 0;
/*  85 */     this.mUnloggedReplay = false;
/*     */   }
/*     */   
/*  88 */   protected Version getVersion() { return this.mVersion; }
/*  89 */   private void setVersion(Version v) { this.mVersion = v; }
/*     */   
/*  91 */   public boolean getUnloggedReplay() { return this.mUnloggedReplay; }
/*  92 */   public void setUnloggedReplay(boolean b) { this.mUnloggedReplay = b; }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void setCommitCallback(RedoCommitCallback callback)
/*     */   {
/* 101 */     this.mCommitCallback = callback;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void start(long timestamp)
/*     */   {
/* 113 */     this.mTimestamp = timestamp;
/* 114 */     if (isStartMarker())
/* 115 */       setTransactionId(this.mRedoLogMgr.getNewTxnId());
/*     */   }
/*     */   
/*     */   public void log() {
/* 119 */     log(true);
/*     */   }
/*     */   
/*     */   public void log(boolean synchronous) {
/* 123 */     this.mRedoLogMgr.log(this, synchronous);
/* 124 */     if (isStartMarker())
/* 125 */       this.mActive = true;
/*     */   }
/*     */   
/*     */   public void setChangeConstraint(boolean checkCreated, int changeId) {
/* 129 */     this.mChangeConstraint = changeId;
/* 130 */     if (!checkCreated)
/* 131 */       this.mChangeConstraint *= -1;
/*     */   }
/*     */   
/*     */   public OperationContext getOperationContext() {
/* 135 */     OperationContext octxt = new OperationContext(this);
/* 136 */     if (this.mChangeConstraint != 0) {
/* 137 */       boolean checkCreated = this.mChangeConstraint >= 0;
/* 138 */       octxt.setChangeConstraint(checkCreated, Math.abs(this.mChangeConstraint));
/*     */     }
/* 140 */     return octxt;
/*     */   }
/*     */   
/*     */   public synchronized void commit() {
/* 144 */     if (this.mActive) {
/* 145 */       this.mActive = false;
/* 146 */       this.mRedoLogMgr.commit(this);
/* 147 */       if (this.mChainedOps != null) {
/* 148 */         for (RedoableOp rop : this.mChainedOps)
/* 149 */           rop.commit();
/* 150 */         this.mChainedOps = null;
/*     */       }
/*     */     }
/*     */     
/* 154 */     synchronized (this.mSBAVGuard) {
/* 155 */       this.mSerializedByteArrayVector = ((byte[][])null);
/*     */     }
/*     */   }
/*     */   
/*     */   public synchronized void abort() {
/* 160 */     if (this.mActive) {
/* 161 */       this.mActive = false;
/* 162 */       this.mRedoLogMgr.abort(this);
/* 163 */       if (this.mChainedOps != null) {
/* 164 */         for (RedoableOp rop : this.mChainedOps)
/* 165 */           rop.abort();
/* 166 */         this.mChainedOps = null;
/*     */       }
/*     */     }
/*     */     
/* 170 */     synchronized (this.mSBAVGuard) {
/* 171 */       this.mSerializedByteArrayVector = ((byte[][])null);
/*     */     }
/*     */   }
/*     */   
/*     */   public boolean isStartMarker()
/*     */   {
/* 177 */     switch (this.mOperation) {
/*     */     case Checkpoint: 
/*     */     case CommitTxn: 
/*     */     case AbortTxn: 
/* 181 */       return false;
/*     */     }
/* 183 */     return true;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public boolean isEndMarker()
/*     */   {
/* 190 */     switch (this.mOperation) {
/*     */     case CommitTxn: 
/*     */     case AbortTxn: 
/* 193 */       return true;
/*     */     }
/* 195 */     return false;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public boolean deferCrashRecovery()
/*     */   {
/* 210 */     return false;
/*     */   }
/*     */   
/*     */   public long getTimestamp() {
/* 214 */     return this.mTimestamp;
/*     */   }
/*     */   
/*     */   protected void setTimestamp(long timestamp) {
/* 218 */     this.mTimestamp = timestamp;
/*     */   }
/*     */   
/*     */   public int getChangeId() {
/* 222 */     return this.mChangeId;
/*     */   }
/*     */   
/*     */   public void setChangeId(int changeId) {
/* 226 */     this.mChangeId = changeId;
/*     */   }
/*     */   
/*     */   public TransactionId getTransactionId() {
/* 230 */     return this.mTxnId;
/*     */   }
/*     */   
/*     */   protected void setTransactionId(TransactionId txnId) {
/* 234 */     this.mTxnId = txnId;
/*     */   }
/*     */   
/*     */   public int getMailboxId() {
/* 238 */     return this.mMailboxId;
/*     */   }
/*     */   
/*     */   public void setMailboxId(int mboxId) {
/* 242 */     this.mMailboxId = mboxId;
/*     */   }
/*     */   
/*     */   protected void serializeHeader(RedoLogOutput out) throws IOException {
/* 246 */     out.write("ZMREDO".getBytes());
/* 247 */     this.mVersion.serialize(out);
/* 248 */     out.writeInt(getOperation().getCode());
/*     */     
/* 250 */     out.writeLong(this.mTimestamp);
/* 251 */     out.writeInt(this.mChangeId);
/* 252 */     out.writeInt(this.mChangeConstraint);
/* 253 */     this.mTxnId.serialize(out);
/*     */     
/* 255 */     out.writeLong(this.mMailboxId);
/*     */   }
/*     */   
/*     */ 
/*     */   private void deserialize(RedoLogInput in)
/*     */     throws IOException
/*     */   {
/* 262 */     this.mTimestamp = in.readLong();
/* 263 */     this.mChangeId = in.readInt();
/* 264 */     this.mChangeConstraint = in.readInt();
/* 265 */     this.mTxnId = new TransactionId();
/* 266 */     this.mTxnId.deserialize(in);
/*     */     
/* 268 */     if (getVersion().atLeast(1, 26)) {
/* 269 */       this.mMailboxId = ((int)in.readLong());
/*     */     } else {
/* 271 */       this.mMailboxId = in.readInt();
/*     */     }
/*     */     
/*     */ 
/* 275 */     deserializeData(in);
/*     */   }
/*     */   
/*     */   public String toString() {
/* 279 */     StringBuffer sb = new StringBuffer("txn ");
/* 280 */     sb.append(this.mTxnId).append(" [").append(getOperation().name());
/* 281 */     sb.append("] ver=").append(this.mVersion);
/* 282 */     sb.append(", tstamp=").append(this.mTimestamp);
/* 283 */     if (this.mChangeId != -1)
/* 284 */       sb.append(", change=").append(this.mChangeId);
/* 285 */     if (this.mChangeConstraint != 0)
/* 286 */       sb.append(", constraint=").append(this.mChangeConstraint);
/* 287 */     String data = getPrintableData();
/* 288 */     if (this.mMailboxId != 0) {
/* 289 */       sb.append(", mailbox=").append(this.mMailboxId);
/* 290 */       if (data != null)
/* 291 */         sb.append(", ").append(data);
/* 292 */     } else if (data != null) {
/* 293 */       sb.append(", ").append(data); }
/* 294 */     return sb.toString();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public MailboxOperation getTxnOpCode()
/*     */   {
/* 305 */     return getOperation();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public MailboxOperation getOperation()
/*     */   {
/* 313 */     return this.mOperation;
/*     */   }
/*     */   
/*     */ 
/*     */   public abstract void redo()
/*     */     throws Exception;
/*     */   
/*     */ 
/*     */   protected abstract String getPrintableData();
/*     */   
/*     */ 
/*     */   protected abstract void serializeData(RedoLogOutput paramRedoLogOutput)
/*     */     throws IOException;
/*     */   
/*     */   protected abstract void deserializeData(RedoLogInput paramRedoLogInput)
/*     */     throws IOException;
/*     */   
/*     */   public InputStream getAdditionalDataStream()
/*     */     throws IOException
/*     */   {
/* 333 */     return null;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static RedoableOp deserializeOp(RedoLogInput in)
/*     */     throws EOFException, IOException
/*     */   {
/* 346 */     RedoableOp op = null;
/* 347 */     byte[] magicBuf = new byte["ZMREDO".length()];
/* 348 */     in.readFully(magicBuf, 0, magicBuf.length);
/* 349 */     String magic = new String(magicBuf);
/* 350 */     if (magic.compareTo("ZMREDO") != 0) {
/* 351 */       throw new IOException("Missing redo item magic marker");
/*     */     }
/* 353 */     Version ver = new Version();
/* 354 */     ver.deserialize(in);
/* 355 */     if (ver.tooHigh()) {
/* 356 */       throw new IOException("Redo op version " + ver + " is higher than the highest known version " + Version.latest());
/*     */     }
/*     */     
/*     */ 
/* 360 */     MailboxOperation opcode = MailboxOperation.fromInt(in.readInt());
/* 361 */     String className = opcode.name();
/* 362 */     if (className != null) {
/* 363 */       Class clz = null;
/*     */       try {
/* 365 */         clz = loadOpClass(sPackageName + "." + className);
/*     */       } catch (ClassNotFoundException e) {
/* 367 */         throw new IOException("ClassNotFoundException for redo operation " + className);
/*     */       }
/*     */       try {
/* 370 */         op = (RedoableOp)clz.newInstance();
/*     */       } catch (InstantiationException e) {
/* 372 */         String msg = "Unable to instantiate " + className;
/* 373 */         mLog.error(msg, e);
/* 374 */         throw new IOException("Unable to instantiate " + className);
/*     */       } catch (IllegalAccessException e) {
/* 376 */         String msg = "IllegalAccessException while instantiating " + className;
/* 377 */         mLog.error(msg, e);
/* 378 */         throw new IOException(msg);
/*     */       }
/*     */     } else {
/* 381 */       throw new IOException("Invalid redo operation code " + opcode);
/*     */     }
/* 383 */     op.setVersion(ver);
/* 384 */     op.deserialize(in);
/* 385 */     return op;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 394 */   protected final Object mSBAVGuard = new Object();
/*     */   private List<RedoableOp> mChainedOps;
/*     */   
/* 397 */   public void setSerializedByteArray(byte[] data) { synchronized (this.mSBAVGuard) {
/* 398 */       if (data != null) {
/* 399 */         this.mSerializedByteArrayVector = new byte[1][];
/* 400 */         this.mSerializedByteArrayVector[0] = data;
/*     */       }
/*     */       else {
/* 403 */         this.mSerializedByteArrayVector = ((byte[][])null);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private byte[] serializeToByteArray()
/*     */     throws IOException
/*     */   {
/* 414 */     ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
/* 415 */     RedoLogOutput out = new RedoLogOutput(baos);
/* 416 */     serializeHeader(out);
/* 417 */     serializeData(out);
/* 418 */     byte[] buf = baos.toByteArray();
/* 419 */     baos.close();
/* 420 */     return buf;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public InputStream getInputStream()
/*     */     throws IOException
/*     */   {
/* 428 */     synchronized (this.mSBAVGuard) {
/* 429 */       if (this.mSerializedByteArrayVector == null)
/* 430 */         setSerializedByteArray(serializeToByteArray());
/* 431 */       List<InputStream> streams = new ArrayList(this.mSerializedByteArrayVector.length + 1);
/* 432 */       for (byte[] array : this.mSerializedByteArrayVector) {
/* 433 */         streams.add(new ByteArrayInputStream(array));
/*     */       }
/* 435 */       InputStream additional = getAdditionalDataStream();
/* 436 */       if (additional != null) {
/* 437 */         streams.add(additional);
/*     */       }
/*     */       
/* 440 */       return new SequenceInputStream(Collections.enumeration(streams));
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized void addChainedOp(RedoableOp subOp)
/*     */   {
/* 449 */     if (this.mChainedOps == null)
/* 450 */       this.mChainedOps = new LinkedList();
/* 451 */     this.mChainedOps.add(subOp);
/*     */   }
/*     */   
/*     */   private static boolean checkSubclasses()
/*     */   {
/* 456 */     boolean allGood = true;
/* 457 */     for (MailboxOperation opcode : EnumSet.allOf(MailboxOperation.class)) {
/* 458 */       String className = opcode.name();
/* 459 */       if (className == null) {
/* 460 */         System.err.println("Invalid redo operation code: " + opcode);
/* 461 */         allGood = false;
/* 462 */       } else if (className.compareTo("UNKNOWN") != 0) {
/* 463 */         Class clz = null;
/*     */         try {
/* 465 */           clz = loadOpClass(sPackageName + "." + className);
/* 466 */           clz.newInstance();
/*     */         }
/*     */         catch (ClassNotFoundException e)
/*     */         {
/* 470 */           System.out.println("Ignoring ClassNotFoundException for redo operation " + className);
/*     */         } catch (InstantiationException e) {
/* 472 */           String msg = "Unable to instantiate " + className + "; Check default constructor is defined.";
/*     */           
/* 474 */           System.err.println(msg);
/* 475 */           e.printStackTrace(System.err);
/* 476 */           allGood = false;
/*     */         } catch (IllegalAccessException e) {
/* 478 */           String msg = "IllegalAccessException while instantiating " + className;
/* 479 */           System.err.println(msg);
/* 480 */           e.printStackTrace(System.err);
/* 481 */           allGood = false;
/*     */         }
/*     */       }
/*     */     }
/* 485 */     return allGood;
/*     */   }
/*     */   
/* 488 */   private static Map<String, Class> sOpClassMap = new HashMap();
/* 489 */   private static List<ClassLoader> sOpClassLoaders = new ArrayList();
/*     */   
/*     */   public static void main(String[] args) {
/* 492 */     if (!checkSubclasses()) {
/* 493 */       System.err.println("Some RedoableOp subclasses are incomplete.  Hint: Make sure the subclass defines a default constructor.");
/*     */       
/*     */ 
/* 496 */       System.exit(1);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static synchronized void registerClassLoader(ClassLoader ldr)
/*     */   {
/* 505 */     mLog.debug("Registering class loader " + ldr);
/* 506 */     for (ClassLoader loader : sOpClassLoaders) {
/* 507 */       if (loader.equals(ldr)) return;
/*     */     }
/* 509 */     sOpClassLoaders.add(ldr);
/*     */   }
/*     */   
/*     */   public static synchronized void deregisterClassLoader(ClassLoader ldr) {
/* 513 */     mLog.debug("Deregistering class loader " + ldr);
/* 514 */     List<String> toRemove = new ArrayList();
/* 515 */     for (Map.Entry<String, Class> entry : sOpClassMap.entrySet()) {
/* 516 */       Class clz = (Class)entry.getValue();
/* 517 */       if (clz.getClassLoader().equals(ldr))
/* 518 */         toRemove.add(entry.getKey());
/*     */     }
/* 520 */     for (String key : toRemove) {
/* 521 */       sOpClassMap.remove(key);
/* 522 */       mLog.debug("Removed " + key + " from redo op class map");
/*     */     }
/* 524 */     for (Iterator iter = sOpClassLoaders.iterator(); iter.hasNext();) {
/* 525 */       ClassLoader loader = (ClassLoader)iter.next();
/* 526 */       if (loader.equals(ldr)) {
/* 527 */         iter.remove();
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private static synchronized Class loadOpClass(String className) throws ClassNotFoundException {
/* 533 */     Class clz = (Class)sOpClassMap.get(className);
/* 534 */     if (clz == null) {
/*     */       try
/*     */       {
/* 537 */         clz = Class.forName(className);
/* 538 */         sOpClassMap.put(className, clz);
/*     */       }
/*     */       catch (ClassNotFoundException e) {
/* 541 */         for (ClassLoader loader : sOpClassLoaders) {
/*     */           try {
/* 543 */             clz = loader.loadClass(className);
/* 544 */             mLog.debug("Loaded class " + className + " using class loader " + loader);
/*     */             
/*     */ 
/* 547 */             sOpClassMap.put(className, clz);
/*     */           }
/*     */           catch (ClassNotFoundException e2) {}
/*     */         }
/* 551 */         if (clz == null) {
/* 552 */           throw e;
/*     */         }
/*     */       }
/*     */     }
/* 556 */     return clz;
/*     */   }
/*     */   
/*     */   public boolean isDeleteOp() {
/* 560 */     return false;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/redolog/op/RedoableOp.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */